﻿// -----------------------------------------------------------------------
// <copyright file="GoFiguration.cs" company="Eric Swanson">
// 
// SUMMARY: *Open source and free to use and modify! 
//          (including Commercially)
// 
// Copyright (c) 2012 Eric Swanson
// 
// Permission is hereby granted, free of charge, to any person obtaining 
// a copy of this software and associated documentation files (the 
// "Software"), to deal in the Software without restriction, including 
// without limitation the rights to use, copy, modify, merge, publish, 
// distribute, sublicense, and/or sell copies of the Software, and to 
// permit persons to whom the Software is furnished to do so, subject to 
// the following conditions:
// 
// The above copyright notice and this permission notice shall be 
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 
// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 
// SOFTWARE.
// </copyright>
// -----------------------------------------------------------------------

namespace GoFiguration
{
	using System;
	using System.Collections.Generic;


#if DOTNET
	using System.Configuration;
#endif

	/// <summary>
	/// Base for a configuration provider.
	/// </summary>
	public abstract class GoFigurationBase
	{
		/// <summary>Determines if a setting key exists in the current configuration.</summary>
		/// <param name="key">The setting key.</param>
		/// <returns><c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.</returns>
		public abstract bool ContainsKey(string key);

		/// <summary>Retrieves the value for the setting using the specified key.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>The setting value.</returns>
		public abstract T Get<T>(string key, T defaultValue);

		/// <summary>Sets the value of the setting identified by the specified key.</summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <returns>The current instance of the GoFiguration object.</returns>
		public abstract GoFigurationBase Set<T>(string key, T value);

		/// <summary>Retrieves the value for the setting using the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <returns>The setting value.</returns>
		public T Get<T>(string key)
		{
			return this.Get<T>(key, default(T));
		}
	}

#if DOTNET
	/// <summary>
	/// Configuration provider for local &lt;appSettings /&gt;.
	/// </summary>
	public class LocalAppSettingsGoFiguration : GoFigurationBase
	{
		private static Func<string, string> prepareKey = key => key.Replace("appSettings:", "");

		/// <summary>
		/// Determines if a setting key exists in the current configuration.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>
		/// <c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.
		/// </returns>
		public override bool ContainsKey(string key)
		{
			return ConfigurationManager.AppSettings[prepareKey(key)] != null;
		}

		/// <summary>
		/// Retrieves the value for the setting using the specified key.
		/// </summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>
		/// The setting value.
		/// </returns>
		public override T Get<T>(string key, T defaultValue)
		{
			if (this.ContainsKey(key))
			{
				return (T)(object)ConfigurationManager.AppSettings[prepareKey(key)];
			}
			else
			{
				return defaultValue;
			}
		}

		/// <summary>
		/// Sets the value of the setting identified by the specified key.
		/// </summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <returns>
		/// The current instance of the GoFiguration object.
		/// </returns>
		public override GoFigurationBase Set<T>(string key, T value)
		{
			throw new InvalidOperationException("Local configuration application settings cannot be modified.");
		}
	}

	/// <summary>
	/// Configuration provider for local &lt;connectionStrings /&gt;.
	/// </summary>
	public class LocalConnectionStringsGoFiguration : GoFigurationBase
	{
		private static Func<string, string> prepareKey = key => key.Replace("connectionStrings:", "");

		/// <summary>
		/// Determines if a setting key exists in the current configuration.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>
		/// <c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.
		/// </returns>
		public override bool ContainsKey(string key)
		{
			return ConfigurationManager.ConnectionStrings[prepareKey(key)] != null;
		}

		/// <summary>
		/// Retrieves the value for the setting using the specified key.
		/// </summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>
		/// The setting value.
		/// </returns>
		public override T Get<T>(string key, T defaultValue)
		{
			if (this.ContainsKey(key))
			{
				return (T)(object)ConfigurationManager.ConnectionStrings[prepareKey(key)].ConnectionString;
			}
			else
			{
				return defaultValue;
			}
		}

		/// <summary>
		/// Sets the value of the setting identified by the specified key.
		/// </summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <returns>
		/// The current instance of the GoFiguration object.
		/// </returns>
		public override GoFigurationBase Set<T>(string key, T value)
		{
			throw new InvalidOperationException("Local configuration connection strings cannot be modified.");
		}
	}
#endif

	/// <summary>Configuration provider for managing in-memory settings.</summary>
	public class InMemoryGoFiguration : GoFigurationBase
	{
		private readonly IDictionary<String, Object> settings = new Dictionary<String, Object>();

		/// <summary>Determines if a setting key exists in the current configuration.</summary>
		/// <param name="key">The setting key.</param>
		/// <returns><c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.</returns>
		public override bool ContainsKey(string key)
		{
			return this.settings.ContainsKey(key);
		}

		/// <summary>Retrieves the value for the setting using the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>The setting value.</returns>
		public override T Get<T>(string key, T defaultValue)
		{
			if (this.ContainsKey(key))
			{
				return (T)this.settings[key];
			}

			return defaultValue;
		}

		/// <summary>Sets the value of the setting identified by the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <returns>The current instance of the GoFiguration object.</returns>
		public override GoFigurationBase Set<T>(string key, T value)
		{
			if (this.ContainsKey(key))
			{
				this.settings[key] = value;
			}
			else
			{
				settings.Add(key, value);
			}

			return this;
		}
	}

	/// <summary>Thrown when a configuration provider could not be found.</summary>
	public class ConfigurationProviderNotFoundException : Exception
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="ConfigurationProviderNotFoundException"/> class.
		/// </summary>
		/// <param name="message">The message.</param>
		public ConfigurationProviderNotFoundException(string message)
			: base(message)
		{

		}
	}

	/// <summary>Configuration provider that delegates management of settings to other providers via a routed lookup.</summary>
	public class RoutedGoFiguration : GoFigurationBase
	{
		private readonly Func<string, GoFigurationBase> providerLookup;

		/// <summary>
		/// Initializes a new instance of the <see cref="RoutedGoFiguration"/> class.
		/// </summary>
		/// <param name="providerLookupStrategy">The provider lookup strategy.</param>
		public RoutedGoFiguration(Func<string, GoFigurationBase> providerLookupStrategy)
			: base()
		{
			this.providerLookup = providerLookupStrategy;
		}

		/// <summary>Determines if a setting key exists in the current configuration.</summary>
		/// <param name="key">The setting key.</param>
		/// <returns><c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.</returns>
		/// <exception cref="ConfigurationProviderNotFoundException">Thrown when a provider could not be found for the specified <paramref name="key" /></exception>
		public override bool ContainsKey(string key)
		{
			var provider = this.providerLookup(key);

			if (provider == null)
			{
				throw new ConfigurationProviderNotFoundException(string.Format("Configuration Provider not found for key {0}", key));
			}

			return provider.ContainsKey(key);
		}

		/// <summary>Retrieves the value for the setting using the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>The setting value.</returns>
		/// <exception cref="ConfigurationProviderNotFoundException">Thrown when a provider could not be found for the specified <paramref name="key" /></exception>
		public override T Get<T>(string key, T defaultValue)
		{
			var provider = this.providerLookup(key);

			if (provider == null)
			{
				throw new ConfigurationProviderNotFoundException(string.Format("Configuration Provider not found for key {0}", key));
			}

			return provider.Get<T>(key, defaultValue);
		}

		/// <summary>Sets the value of the setting identified by the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <exception cref="ConfigurationProviderNotFoundException">Thrown when a provider could not be found for the specified <paramref name="key" /></exception>
		/// <returns>The current instance of the GoFiguration object.</returns>
		public override GoFigurationBase Set<T>(string key, T value)
		{
			var provider = this.providerLookup(key);

			if (provider == null)
			{
				throw new ConfigurationProviderNotFoundException(string.Format("Configuration Provider not found for key {0}", key));
			}

			provider.Set<T>(key, value);

			return this;
		}
	}

	/// <summary>Provides simplified and abstracted access to configuration data management.</summary>
	public class GoFigure
	{
		// thread-safe lock object for updating the provider
		private static readonly object providerLock = new Object();

#if DOTNET
		// config provider for <appSettings>
		private static readonly GoFigurationBase appSettingsProvider = new LocalAppSettingsGoFiguration();

		// config provider for <connectionStrings>
		private static readonly GoFigurationBase connectionStringsProvider = new LocalConnectionStringsGoFiguration();

		// in-memory provider
		private static readonly GoFigurationBase inMemoryProvider = new InMemoryGoFiguration();

		// provider lookup strategy
		private static readonly Func<string, GoFigurationBase> providerLookupStrategy =
			key =>
			{
				// delegate <appSettings>
				if (key.StartsWith("appSettings:")) return appSettingsProvider;
				// delegate <connectionStrings>
				if (key.StartsWith("connectionStrings:")) return connectionStringsProvider;
				// fallback on in-memory
				return inMemoryProvider;
			};

		// factory for the default backing store for config info
		private static readonly Func<GoFigurationBase> loadDefaultProvider = () => new RoutedGoFiguration(key => providerLookupStrategy(key));

#else

		// factory for the default backing store for config info
		private static readonly Func<GoFigurationBase> loadDefaultProvider = () => new InMemoryGoFiguration();

#endif

		// the backing store for config info
		private static GoFigurationBase provider = loadDefaultProvider();

		/// <summary>
		/// Prevents a default instance of the <see cref="GoFigure"/> class from being created.
		/// </summary>
		private GoFigure()
		{
		}

		/// <summary>Loads the default GoFigure configuration provider.</summary>
		/// <returns>The default instance of the GoFiguration provider.</returns>
		public static GoFigurationBase LoadDefaultProvider()
		{
			lock (providerLock)
			{
				provider = loadDefaultProvider();
			}

			return provider;
		}

		/// <summary>Sets the configuration provider using the specified <paramref name="newProvider"/>.</summary>
		/// <param name="newProvider">The new configuration provider to use.</param>
		/// <returns>The current instance of the GoFiguration provider.</returns>
		public static GoFigurationBase GetConfigurationFrom(GoFigurationBase newProvider)
		{
			lock (providerLock)
			{
				provider = newProvider;
			}

			return provider;
		}

		/// <summary>Determines if a setting key exists in the current configuration.</summary>
		/// <param name="key">The setting key.</param>
		/// <returns><c>true</c> if a matching setting was found in the current configuration, otherwise <c>false</c>.</returns>
		public static bool ContainsKey(string key)
		{
			return provider.ContainsKey(key);
		}

		/// <summary>Retrieves the value for the setting using the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <returns>The setting value.</returns>
		public static T Get<T>(string key)
		{
			return provider.Get<T>(key);
		}

		/// <summary>Retrieves the value for the setting using the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value expected.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="defaultValue">The default value if the setting is not found.</param>
		/// <returns>The setting value.</returns>
		public static T Get<T>(string key, T defaultValue)
		{
			return provider.Get<T>(key, defaultValue);
		}

		/// <summary>Sets the value of the setting identified by the specified <paramref name="key"/>.</summary>
		/// <typeparam name="T">The type of the setting value.</typeparam>
		/// <param name="key">The setting key.</param>
		/// <param name="value">The setting value.</param>
		/// <returns>The current instance of the GoFiguration object.</returns>
		public static GoFigurationBase Set<T>(string key, T value)
		{
			return provider.Set<T>(key, value);
		}

#if DOTNET

		/// <summary>Retrieves the value for the application setting using the specified <paramref name="key"/>.</summary>
		/// <param name="key">The application setting key.</param>
		/// <returns>The application setting value.</returns>
		public static string GetAppSetting(string key)
		{
			var fullKey = "appSettings:" + key;
			return provider.Get<string>(fullKey);
		}

		/// <summary>Retrieves the value for the application setting using the specified <paramref name="key"/>.</summary>
		/// <param name="key">The application setting key.</param>
		/// <param name="defaultValue">The default value if the application setting is not found.</param>
		/// <returns>The application setting value.</returns>
		public static string GetAppSetting(string key, string defaultValue)
		{
			var fullKey = "appSettings:" + key;
			return provider.Get<string>(fullKey, defaultValue);
		}

		/// <summary>Retrieves the value for the connection string using the specified <paramref name="key"/>.</summary>
		/// <param name="key">The connection string key.</param>
		/// <returns>The connection string value.</returns>
		public static string GetConnectionString(string key)
		{
			var fullKey = "connectionStrings:" + key;
			return provider.Get<string>(fullKey);
		}

		/// <summary>Retrieves the value for the connection string using the specified <paramref name="key"/>.</summary>
		/// <param name="key">The connection string key.</param>
		/// <param name="defaultValue">The default value if the connection string is not found.</param>
		/// <returns>The connection string value.</returns>
		public static string GetConnectionString(string key, string defaultValue)
		{
			var fullKey = "connectionStrings:" + key;
			return provider.Get<string>(fullKey, defaultValue);
		}

#endif
	}
}

namespace GoFiguration.Services.Client
{
	using System.Diagnostics;
	using System.ServiceModel;
	using System.ServiceModel.Channels;

#if SILVERLIGHT
	using System;
	using System.ComponentModel;
	using System.Net;
	using System.Threading;
#endif

	/// <summary>
	/// Contract for a GoFigure WCF service.
	/// </summary>
	[ServiceContract(ConfigurationName = "GoFigure.IGoFigureService", Namespace = "http://gofigure.codeplex.com")]
	public interface IGoFigureService
	{
#if DOTNET
		/// <summary>
		/// Gets the configuration setting value as XML using the specified <paramref name="key"/>.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>The configuration setting value as an XML <see cref="System.String"/>.</returns>
		[OperationContract(Action = "http://gofigure.codeplex.com/IGoFigureService/GetAsXML", ReplyAction = "http://gofigure.codeplex.com/IGoFigureService/GetAsXMLResponse")]
		string GetAsXML(string key);

		/// <summary>
		/// Gets the configuration setting value as JSON using the specified <paramref name="key"/>.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>The configuration setting value as a JSON <see cref="System.String"/>.</returns>
		[OperationContract(Action = "http://gofigure.codeplex.com/IGoFigureService/GetAsJSON", ReplyAction = "http://gofigure.codeplex.com/IGoFigureService/GetAsJSONResponse")]
		string GetAsJSON(string key);
#endif

#if SILVERLIGHT
		/// <summary>
		/// Begins the get as XML.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		[OperationContract(AsyncPattern = true, ReplyAction = "http://gofigure.codeplex.com/IGoFigureService/GetAsXMLResponse")]
		IAsyncResult BeginGetAsXML(string key, AsyncCallback callback, object asyncState);

		/// <summary>
		/// Ends the get as XML.
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>The XML.</returns>
		string EndGetAsXML(IAsyncResult result);

		/// <summary>
		/// Begins the get as JSON.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		[OperationContract(AsyncPattern = true, Action = "http://gofigure.codeplex.com/IGoFigureService/GetAsJSON", ReplyAction = "http://gofigure.codeplex.com/IGoFigureService/GetAsJSONResponse")]
		IAsyncResult BeginGetAsJSON(string key, AsyncCallback callback, object asyncState);

		/// <summary>
		/// Ends the get as JSON.
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>The JSON.</returns>
		string EndGetAsJSON(IAsyncResult result);
#endif
	}

	/// <summary>
	/// Contract for a GoFigure service channel.
	/// </summary>
	public interface IGoFigureServiceChannel : IGoFigureService, IClientChannel
	{
	}

#if DOTNET
	/// <summary>
	/// GoFigure service client.
	/// </summary>
	[DebuggerStepThrough]
	public partial class GoFigureServiceClient : ClientBase<IGoFigureService>, IGoFigureService
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		public GoFigureServiceClient()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		public GoFigureServiceClient(string endpointConfigurationName) :
			base(endpointConfigurationName)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(string endpointConfigurationName, string remoteAddress) :
			base(endpointConfigurationName, remoteAddress)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) :
			base(endpointConfigurationName, remoteAddress)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="binding">The binding.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(Binding binding, EndpointAddress remoteAddress) :
			base(binding, remoteAddress)
		{
		}

		/// <summary>
		/// Gets the configuration setting value as XML using the specified <paramref name="key"/>.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>
		/// The configuration setting value as an XML <see cref="System.String"/>.
		/// </returns>
		public string GetAsXML(string key)
		{
			return base.Channel.GetAsXML(key);
		}

		/// <summary>
		/// Gets the configuration setting value as JSON using the specified <paramref name="key"/>.
		/// </summary>
		/// <param name="key">The setting key.</param>
		/// <returns>
		/// The configuration setting value as a JSON <see cref="System.String"/>.
		/// </returns>
		public string GetAsJSON(string key)
		{
			return base.Channel.GetAsJSON(key);
		}
	}
#endif

#if SILVERLIGHT
	/// <summary>
	/// Get XML completed event arguments.
	/// </summary>
	[DebuggerStepThrough]
	public partial class GetAsXMLCompletedEventArgs : AsyncCompletedEventArgs
	{
		// list of results
		private object[] results;

		/// <summary>
		/// Initializes a new instance of the <see cref="GetAsXMLCompletedEventArgs"/> class.
		/// </summary>
		/// <param name="results">The results.</param>
		/// <param name="exception">The exception.</param>
		/// <param name="cancelled">if set to <c>true</c> [cancelled].</param>
		/// <param name="userState">State of the user.</param>
		public GetAsXMLCompletedEventArgs(object[] results, Exception exception, bool cancelled, object userState) :
			base(exception, cancelled, userState)
		{
			this.results = results;
		}

		/// <summary>
		/// Gets the result.
		/// </summary>
		public string Result
		{
			get
			{
				base.RaiseExceptionIfNecessary();

				return ((string)(this.results[0]));
			}
		}
	}

	/// <summary>
	/// Get JSON completed event arguments.
	/// </summary>
	[DebuggerStepThrough]
	public partial class GetAsJSONCompletedEventArgs : AsyncCompletedEventArgs
	{
		// list of results
		private object[] results;

		/// <summary>
		/// Initializes a new instance of the <see cref="GetAsJSONCompletedEventArgs"/> class.
		/// </summary>
		/// <param name="results">The results.</param>
		/// <param name="exception">The exception.</param>
		/// <param name="cancelled">if set to <c>true</c> [cancelled].</param>
		/// <param name="userState">State of the user.</param>
		public GetAsJSONCompletedEventArgs(object[] results, Exception exception, bool cancelled, object userState) :
			base(exception, cancelled, userState)
		{
			this.results = results;
		}

		/// <summary>
		/// Gets the result.
		/// </summary>
		public string Result
		{
			get
			{
				base.RaiseExceptionIfNecessary();

				return ((string)(this.results[0]));
			}
		}
	}

	/// <summary>
	/// The GoFigure service client.
	/// </summary>
	[DebuggerStepThrough]
	public partial class GoFigureServiceClient : ClientBase<IGoFigureService>, IGoFigureService
	{
		// on begin "GetAsXML"
		private BeginOperationDelegate onBeginGetAsXMLDelegate;

		// on end "GetAsXML"
		private EndOperationDelegate onEndGetAsXMLDelegate;

		// on completed "GetAsXML"
		private SendOrPostCallback onGetAsXMLCompletedDelegate;

		// on begin "GetAsJSON"
		private BeginOperationDelegate onBeginGetAsJSONDelegate;

		// on end "GetAsJSON"
		private EndOperationDelegate onEndGetAsJSONDelegate;

		// on completed "GetAsJSON"
		private SendOrPostCallback onGetAsJSONCompletedDelegate;

		// on begin "Open"
		private BeginOperationDelegate onBeginOpenDelegate;

		// on end "Open"
		private EndOperationDelegate onEndOpenDelegate;

		// on completed "Open"
		private SendOrPostCallback onOpenCompletedDelegate;

		// on begin "Close"
		private BeginOperationDelegate onBeginCloseDelegate;

		// on end "Close"
		private EndOperationDelegate onEndCloseDelegate;

		// on completed "Close"
		private SendOrPostCallback onCloseCompletedDelegate;

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		public GoFigureServiceClient()
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		public GoFigureServiceClient(string endpointConfigurationName) :
			base(endpointConfigurationName)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(string endpointConfigurationName, string remoteAddress) :
			base(endpointConfigurationName, remoteAddress)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="endpointConfigurationName">Name of the endpoint configuration.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(string endpointConfigurationName, EndpointAddress remoteAddress) :
			base(endpointConfigurationName, remoteAddress)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="GoFigureServiceClient"/> class.
		/// </summary>
		/// <param name="binding">The binding.</param>
		/// <param name="remoteAddress">The remote address.</param>
		public GoFigureServiceClient(Binding binding, EndpointAddress remoteAddress) :
			base(binding, remoteAddress)
		{
		}

		/// <summary>
		/// Gets or sets the cookie container.
		/// </summary>
		/// <value>
		/// The cookie container.
		/// </value>
		public CookieContainer CookieContainer
		{
			get
			{
				var httpCookieContainerManager = this.InnerChannel.GetProperty<IHttpCookieContainerManager>();

				if ((httpCookieContainerManager != null))
				{
					return httpCookieContainerManager.CookieContainer;
				}
				else
				{
					return null;
				}
			}

			set
			{
				var httpCookieContainerManager = this.InnerChannel.GetProperty<IHttpCookieContainerManager>();

				if ((httpCookieContainerManager != null))
				{
					httpCookieContainerManager.CookieContainer = value;
				}
				else
				{
					throw new InvalidOperationException("Unable to set the CookieContainer. Please make sure the binding contains an HttpCookieContainerBindingElement.");
				}
			}
		}

		/// <summary>
		/// Occurs when [get as XML completed].
		/// </summary>
		public event EventHandler<GetAsXMLCompletedEventArgs> GetAsXMLCompleted;

		/// <summary>
		/// Occurs when [get as JSON completed].
		/// </summary>
		public event EventHandler<GetAsJSONCompletedEventArgs> GetAsJSONCompleted;

		/// <summary>
		/// Occurs when [open completed].
		/// </summary>
		public event EventHandler<AsyncCompletedEventArgs> OpenCompleted;

		/// <summary>
		/// Occurs when [close completed].
		/// </summary>
		public event EventHandler<AsyncCompletedEventArgs> CloseCompleted;

		/// <summary>
		/// Begins the get as XML.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		IAsyncResult IGoFigureService.BeginGetAsXML(string key, AsyncCallback callback, object asyncState)
		{
			return base.Channel.BeginGetAsXML(key, callback, asyncState);
		}

		/// <summary>
		/// Ends the get as XML.
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>The XML.</returns>
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		string IGoFigureService.EndGetAsXML(IAsyncResult result)
		{
			return base.Channel.EndGetAsXML(result);
		}

		/// <summary>
		/// Called when [begin get as XML].
		/// </summary>
		/// <param name="inValues">The in values.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchoronous result of the call.</returns>
		private IAsyncResult OnBeginGetAsXML(object[] inValues, AsyncCallback callback, object asyncState)
		{
			string key = ((string)(inValues[0]));

			return ((IGoFigureService)(this)).BeginGetAsXML(key, callback, asyncState);
		}

		/// <summary>
		/// Called when [end get as XML].
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>An object array containing the return value.</returns>
		private object[] OnEndGetAsXML(IAsyncResult result)
		{
			string retVal = ((IGoFigureService)(this)).EndGetAsXML(result);

			return new object[] { retVal };
		}

		/// <summary>
		/// Called when [get as XML completed].
		/// </summary>
		/// <param name="state">The state.</param>
		private void OnGetAsXMLCompleted(object state)
		{
			if ((this.GetAsXMLCompleted != null))
			{
				InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));

				this.GetAsXMLCompleted(this, new GetAsXMLCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
			}
		}

		/// <summary>
		/// Gets as XML async.
		/// </summary>
		/// <param name="key">The key.</param>
		public void GetAsXMLAsync(string key)
		{
			this.GetAsXMLAsync(key, null);
		}

		/// <summary>
		/// Gets as XML async.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="userState">State of the user.</param>
		public void GetAsXMLAsync(string key, object userState)
		{
			if ((this.onBeginGetAsXMLDelegate == null))
			{
				this.onBeginGetAsXMLDelegate = new BeginOperationDelegate(this.OnBeginGetAsXML);
			}

			if ((this.onEndGetAsXMLDelegate == null))
			{
				this.onEndGetAsXMLDelegate = new EndOperationDelegate(this.OnEndGetAsXML);
			}

			if ((this.onGetAsXMLCompletedDelegate == null))
			{
				this.onGetAsXMLCompletedDelegate = new SendOrPostCallback(this.OnGetAsXMLCompleted);
			}

			base.InvokeAsync(
				this.onBeginGetAsXMLDelegate,
				new object[] { key },
				this.onEndGetAsXMLDelegate,
				this.onGetAsXMLCompletedDelegate,
				userState);
		}

		/// <summary>
		/// Begins the get as JSON.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		IAsyncResult IGoFigureService.BeginGetAsJSON(string key, AsyncCallback callback, object asyncState)
		{
			return base.Channel.BeginGetAsJSON(key, callback, asyncState);
		}

		/// <summary>
		/// Ends the get as JSON.
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>The JSON.</returns>
		[EditorBrowsable(EditorBrowsableState.Advanced)]
		string IGoFigureService.EndGetAsJSON(IAsyncResult result)
		{
			return base.Channel.EndGetAsJSON(result);
		}

		/// <summary>
		/// Called when [begin get as JSON].
		/// </summary>
		/// <param name="inValues">The in values.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		private IAsyncResult OnBeginGetAsJSON(object[] inValues, AsyncCallback callback, object asyncState)
		{
			string key = ((string)(inValues[0]));

			return ((IGoFigureService)(this)).BeginGetAsJSON(key, callback, asyncState);
		}

		/// <summary>
		/// Called when [end get as JSON].
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>An object array containing the return value.</returns>
		private object[] OnEndGetAsJSON(IAsyncResult result)
		{
			string retVal = ((IGoFigureService)(this)).EndGetAsJSON(result);

			return new object[] { retVal };
		}

		/// <summary>
		/// Called when [get as JSON completed].
		/// </summary>
		/// <param name="state">The state.</param>
		private void OnGetAsJSONCompleted(object state)
		{
			if ((this.GetAsJSONCompleted != null))
			{
				InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));

				this.GetAsJSONCompleted(this, new GetAsJSONCompletedEventArgs(e.Results, e.Error, e.Cancelled, e.UserState));
			}
		}

		/// <summary>
		/// Gets as JSON async.
		/// </summary>
		/// <param name="key">The key.</param>
		public void GetAsJSONAsync(string key)
		{
			this.GetAsJSONAsync(key, null);
		}

		/// <summary>
		/// Gets as JSON async.
		/// </summary>
		/// <param name="key">The key.</param>
		/// <param name="userState">State of the user.</param>
		public void GetAsJSONAsync(string key, object userState)
		{
			if ((this.onBeginGetAsJSONDelegate == null))
			{
				this.onBeginGetAsJSONDelegate = new BeginOperationDelegate(this.OnBeginGetAsJSON);
			}

			if ((this.onEndGetAsJSONDelegate == null))
			{
				this.onEndGetAsJSONDelegate = new EndOperationDelegate(this.OnEndGetAsJSON);
			}

			if ((this.onGetAsJSONCompletedDelegate == null))
			{
				this.onGetAsJSONCompletedDelegate = new SendOrPostCallback(this.OnGetAsJSONCompleted);
			}

			base.InvokeAsync(
				this.onBeginGetAsJSONDelegate,
				new object[] { key },
				this.onEndGetAsJSONDelegate,
				this.onGetAsJSONCompletedDelegate,
				userState);
		}

		/// <summary>
		/// Called when [begin open].
		/// </summary>
		/// <param name="inValues">The in values.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		private IAsyncResult OnBeginOpen(object[] inValues, AsyncCallback callback, object asyncState)
		{
			return ((ICommunicationObject)(this)).BeginOpen(callback, asyncState);
		}

		/// <summary>
		/// Called when [end open].
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>Always returns <c>null</c>.</returns>
		private object[] OnEndOpen(IAsyncResult result)
		{
			((ICommunicationObject)(this)).EndOpen(result);

			return null;
		}

		/// <summary>
		/// Called when [open completed].
		/// </summary>
		/// <param name="state">The state.</param>
		private void OnOpenCompleted(object state)
		{
			if ((this.OpenCompleted != null))
			{
				InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));

				this.OpenCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
			}
		}

		/// <summary>
		/// Opens the async.
		/// </summary>
		public void OpenAsync()
		{
			this.OpenAsync(null);
		}

		/// <summary>
		/// Opens the async.
		/// </summary>
		/// <param name="userState">State of the user.</param>
		public void OpenAsync(object userState)
		{
			if ((this.onBeginOpenDelegate == null))
			{
				this.onBeginOpenDelegate = new BeginOperationDelegate(this.OnBeginOpen);
			}

			if ((this.onEndOpenDelegate == null))
			{
				this.onEndOpenDelegate = new EndOperationDelegate(this.OnEndOpen);
			}

			if ((this.onOpenCompletedDelegate == null))
			{
				this.onOpenCompletedDelegate = new SendOrPostCallback(this.OnOpenCompleted);
			}

			base.InvokeAsync(this.onBeginOpenDelegate, null, this.onEndOpenDelegate, this.onOpenCompletedDelegate, userState);
		}

		/// <summary>
		/// Called when [begin close].
		/// </summary>
		/// <param name="inValues">The in values.</param>
		/// <param name="callback">The callback.</param>
		/// <param name="asyncState">State of the async.</param>
		/// <returns>The asynchronous result of the call.</returns>
		private IAsyncResult OnBeginClose(object[] inValues, AsyncCallback callback, object asyncState)
		{
			return ((ICommunicationObject)(this)).BeginClose(callback, asyncState);
		}

		/// <summary>
		/// Called when [end close].
		/// </summary>
		/// <param name="result">The result.</param>
		/// <returns>Always returns <c>null</c>.</returns>
		private object[] OnEndClose(IAsyncResult result)
		{
			((ICommunicationObject)(this)).EndClose(result);

			return null;
		}

		/// <summary>
		/// Called when [close completed].
		/// </summary>
		/// <param name="state">The state.</param>
		private void OnCloseCompleted(object state)
		{
			if ((this.CloseCompleted != null))
			{
				InvokeAsyncCompletedEventArgs e = ((InvokeAsyncCompletedEventArgs)(state));

				this.CloseCompleted(this, new AsyncCompletedEventArgs(e.Error, e.Cancelled, e.UserState));
			}
		}

		/// <summary>
		/// Closes the async.
		/// </summary>
		public void CloseAsync()
		{
			this.CloseAsync(null);
		}

		/// <summary>
		/// Closes the async.
		/// </summary>
		/// <param name="userState">State of the user.</param>
		public void CloseAsync(object userState)
		{
			if ((this.onBeginCloseDelegate == null))
			{
				this.onBeginCloseDelegate = new BeginOperationDelegate(this.OnBeginClose);
			}

			if ((this.onEndCloseDelegate == null))
			{
				this.onEndCloseDelegate = new EndOperationDelegate(this.OnEndClose);
			}

			if ((this.onCloseCompletedDelegate == null))
			{
				this.onCloseCompletedDelegate = new SendOrPostCallback(this.OnCloseCompleted);
			}

			base.InvokeAsync(this.onBeginCloseDelegate, null, this.onEndCloseDelegate, this.onCloseCompletedDelegate, userState);
		}

		/// <summary>
		/// Creates the service channel.
		/// </summary>
		/// <returns>A new instance of the service channel.</returns>
		protected override IGoFigureService CreateChannel()
		{
			return new GoFigureServiceClientChannel(this);
		}

		/// <summary>
		/// The service channel implementation.
		/// </summary>
		private class GoFigureServiceClientChannel : ChannelBase<IGoFigureService>, IGoFigureService
		{
			/// <summary>
			/// Initializes a new instance of the <see cref="GoFigureServiceClientChannel"/> class.
			/// </summary>
			/// <param name="client">The client.</param>
			public GoFigureServiceClientChannel(ClientBase<IGoFigureService> client) :
				base(client)
			{
			}

			/// <summary>
			/// Begins the get as XML.
			/// </summary>
			/// <param name="key">The key.</param>
			/// <param name="callback">The callback.</param>
			/// <param name="asyncState">State of the async.</param>
			/// <returns>The asynchronous result of the call.</returns>
			public IAsyncResult BeginGetAsXML(string key, AsyncCallback callback, object asyncState)
			{
				object[] _args = new object[1];
				_args[0] = key;

				var _result = base.BeginInvoke("GetAsXML", _args, callback, asyncState);

				return _result;
			}

			/// <summary>
			/// Ends the get as XML.
			/// </summary>
			/// <param name="result">The result.</param>
			/// <returns>The XML.</returns>
			public string EndGetAsXML(IAsyncResult result)
			{
				object[] _args = new object[0];
				string _result = ((string)(base.EndInvoke("GetAsXML", _args, result)));
				return _result;
			}

			/// <summary>
			/// Begins the get as JSON.
			/// </summary>
			/// <param name="key">The key.</param>
			/// <param name="callback">The callback.</param>
			/// <param name="asyncState">State of the async.</param>
			/// <returns>The asynchronous result of the call.</returns>
			public IAsyncResult BeginGetAsJSON(string key, AsyncCallback callback, object asyncState)
			{
				object[] _args = new object[1];

				_args[0] = key;

				var _result = base.BeginInvoke("GetAsJSON", _args, callback, asyncState);

				return _result;
			}

			/// <summary>
			/// Ends the get as JSON.
			/// </summary>
			/// <param name="result">The result.</param>
			/// <returns>The JSOn.</returns>
			public string EndGetAsJSON(IAsyncResult result)
			{
				object[] _args = new object[0];
				string _result = ((string)(base.EndInvoke("GetAsJSON", _args, result)));

				return _result;
			}
		}
	}
#endif
}